% function of conv_decode using viterbi algorithm
% convolutional code of rate 1/2, Generator polynomial [7,5] octal

clear

N = 10^4; % number of bits or symbols 

Eb_No_dB = [0:10];
snr_val = sqrt(10.^(-Eb_No_dB./10));

refHard = [0 0; 0 1; 1 0; 1 1];
refsoft = -1*[-1 -1; -1 1; 1 -1; -1 -1];

pcOut = [0 0 1 0;...
		 0 0 1 0;...
	 	 0 0 0 1;...
		 0 0 0 1]
for ii = 1:length(Eb_No_dB)
	src = round(rand(1,N)); %generate the source bit 0,1
	g1 = [1 1 1]; % generator (7, 5)  octal
	g2 = [1 0 1]; 
	csrc = conv1(src, g1, g2); % conv_encoding
	
	cmod = 2 * csrc - 1; % modulation BPSK
	
	n = (1/sqrt(2)) * (randn(1, length(csrc)) + j * randn(1,length(csrc))); % awgn, 0dB variance

	r = cmod + snr_val(ii)*n; % receive signal

	% receiver decision
	rHard = real(r) > 0; % hard decision
	rSoft = real(r); % soft decision

	% viterbi decoding
	pmHard = zeros(4, 1); % hard path metric
	svHard_whole = zeros(4, length(r)/2); % survival path 

	pmSoft = zeros(4,1); % soft path metric
	svSoft = zeros(4, length(r)/2); % soft survival path

	for ll = 1:length(r) % loop of the path
		rHard = rHard((ll-1)*2 + 1:ll*2);
		rSoft = rSoft((ll-1)*2 + 1:ll*2);

		% caculate the Hamming distance and the Euclid distance
		rHard = repmat(rHard, 4, 1);
		rSoft = repmat(rSoft, 4, 1);
		hammingDistance = sum(xor(rHard, refHard), 2);
		eculidDistance = sum(rSoft.*refSoft);

		if (ll == 1 || ll == 2)
			% branch metric for state 0
			bm1Hard = pmHard(1, 1) + hammingDistance(1);
			pmHardn(1, 1) = bm1Hard;
			svHard = 1;

			% branch for state 1
			bm1Hard = pmHard(3, 1) + hammingDistance(3);
			pmHardn(2, 1) = bm1Hard;
			svHard(2, 1) = 3;

			% branch for state 2

			bm1Hard = pmHard(1, 1) + hammingDistance(4);
			pmHardn(3, 1) = bm1Hard;
			svHard(3, 1) = 1;

			% branch for state 3

			bm1Hard = pmHard(3, 1) + hammingDistance(2);
			pmHardn(4, 1) = bm1Hard;
			svHard(4, 1) = 3;

		else

			% branch for state0 00, two way to state 0
			bm1Hard = pmHard(1, 1) + hammingDistance(1); % from state0 00 output 00
			bm1Hard = pmHard(2, 1) + hammingDistance(4); % from state1 01 output 11
			[pmHardn(1, 1) index] = min([bm1Hard bm2Hard]);
			svHard(1, 1) = index;

			% branch for state1 01
			bm1Hard = pmHard(3, 1) + hammingDistance(3);
			bm2Hard = pmHard(4, 1) + hammingDistance(2);
			[pmHardn(2, 1) index] = min([bm1Hard bm2Hard]);
			svHard(2, 1) = index + 2;


			% branch for state2 10
			bm1Hard = pmHard(1,1) + hammingDistance(3);
			bm2Hard = pmHard(2,1) + hammingDistance(2);
			[pmHardn(3, 1) index] = min([bm1Hard bm2Hard]);
			svHard(3, 1) = index;

			% branch for state3 11
			bm1Hard = pmHard(3, 1) + hammingDistance(2);
			bm2Hard = pmHard(4, 1) + hammingDistance(3);
		   [pmHardn(4, 1) index] = min([bm1Hard bm2Hard]);
		   svHard(4, 1)	= index + 2;

	   end

	   pmHard = pmHardn;
	   svHard_whole(:, ll) = svHard;
	   pmSoft = pmSoftn;
	   svSoft_whole(:, ll) = svSoft;
   end

   % trace back
	currHardState = 1;
	currSoftState = 1;

	hardOut = zeros(1, length(r)/2);
	softOut = zeros(1, length(r)/2);

	for jj = length(r)/2:-1:1
		preHardState = svHard_whole(currHardState, jj);
		hardOut(jj) = pcOut(preHardState, currHardState);
		currHardState = preHardState;
	end

	% caculating the errors
	nErrHardViterbi(ii) = 




















	




	
	


